package net.beaconcontroller.comp416project.model;


import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Observer;

import net.beaconcontroller.comp416project.core.SwitchCore;
import net.beaconcontroller.comp416project.view.View;
import net.beaconcontroller.core.IOFSwitch;
import net.beaconcontroller.comp416project.data.*;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFPort;

public class Model {
	private static ArrayList<Observer> listeners = new ArrayList<Observer>(); //listeners = observers = subscriber
	private static HashMap<String,OFFlowMod> flowMap;
	private static HashMap<OFFlowMod,String> stringMap;
	private IOFSwitch sw;
	private static int last;
	private static int tmp=0;
	private static int bufferid;
	
	
	public Model(IOFSwitch sw){
		this.sw=sw;
		View view = new View(this);
		view.setSize(1500,500 );
		view.setResizable(true);
		view.setVisible(true);
		view.setLocationRelativeTo(null);
		
	}
	
	public void addObserver (Observer o) { //addObserver = addListener = register
	      listeners.add(o);
	}
	
	public void removeObserver (Observer o) {
	      listeners.remove(o);
	}
	
	public static void setFlowMap(){
		
		if(stringMap!=null&&flowMap!=null){
			stringMap.clear();
			flowMap.clear();
		}
		return;
	
	}
	
	public static void setBufferied(int buID){
		bufferid=buID;
	}
	
	public static void setFlowMap(HashMap<String,OFFlowMod> flow, HashMap<OFFlowMod, String> string){
		
		ArrayList<OFFlowMod> flowlist = new ArrayList<OFFlowMod>(string.keySet());
		//ArrayList<String> stringlist  = new ArrayList<String>(flow.keySet());
		
		if(stringMap==null&&flowMap==null){
			stringMap=string;
			flowMap=flow;
		}
		else{
			last= stringMap.size();
			stringMap.clear();
			flowMap.clear();
			for(int i=0;i<flowlist.size()||i<stringMap.size();i++){
				flowMap.remove(stringMap.get(flowlist.get(i)));
				stringMap.remove(flowlist.get(i));
				flowMap.put(string.get(flowlist.get(i)),flow.get(string.get(flowlist.get(i))));
				stringMap.put(flow.get(string.get(flowlist.get(i))),string.get(flowlist.get(i)));
				
			}
		}
		//System.out.println(flowlist.size());
		//System.out.println(flowMap.size());
		//System.out.println("I changed the flow Map in Model");
			updatePortInfo();
	
		tmp++;
	}
	
	
	
	public static HashMap<String,OFFlowMod> getFlowMap(){
		return flowMap;
	}
	
	
	public boolean addFlow(OFFlowMod fm){
		int a=0;
		while(flowMap.containsKey("flow"+a)){
			a++;
		}
		flowMap.put("flow"+a,fm);
		fm.setCommand(OFFlowMod.OFPFC_MODIFY);
		try {
			sw.getOutputStream().write(fm);
			SwitchCore.upadteFlowMap(sw);
			updatePortInfo();
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return false;
		}
		
	}
	
	public boolean modifyFlow(String flowName,OFFlowMod fm){
		
		fm.setCommand(OFFlowMod.OFPFC_MODIFY);
		flowMap.get(flowName).setBufferId(bufferid);
		flowMap.get(flowName).setOutPort(OFPort.OFPP_NONE);
		flowMap.get(flowName).setPriority((short) 0);
		flowMap.put(flowName, fm);
		try {
			sw.getOutputStream().write(fm);
			flowMap.remove(flowName);
			SwitchCore.upadteFlowMap(sw);
			updatePortInfo();
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return false;
		}
	}
	
	public boolean deleteFlow(String flowName){
		flowMap.get(flowName).setCommand(OFFlowMod.OFPFC_DELETE);
		flowMap.get(flowName).setBufferId(bufferid);
		flowMap.get(flowName).setOutPort(OFPort.OFPP_NONE);
		flowMap.get(flowName).setPriority((short) 0);
		try {
			System.out.println(flowMap.get(flowName).toString());
			sw.getOutputStream().write(flowMap.get(flowName));
			SwitchCore.upadteFlowMap(sw);
			updatePortInfo();
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return false;
		}
		
	}
	
	public static void updatePortInfo(){
		 Iterator<Observer> i = listeners.iterator();
	       while (i.hasNext()) {
	             Observer o = (Observer) i.next();
	             ((View)o).update(flowMap);
	        }
	}
//	
//	public static void updateShow(){
////		 Iterator<Observer> i = listeners.iterator();
////	       while (i.hasNext()) {
////	             Observer o = (Observer) i.next();
////	             ((View)o).updateMutiple();
////	        }
//	}
//	
//	
//	public static void MapToFlow(HashMap<String,DataFlowMod> flowMap){
//		
////		for(int i=0;i<flowMap.size();i++){
////			String name = "flow"+(i+1);
////			updateSpeed(flowMap.get(name).getSpeed(), i+1, flowMap.get(name).getSpeed()+"");
////		}
//	}
//
//	public static void updateSpeed(double data, int id, String result){
////		 Iterator<Observer> i = listeners.iterator();
////	       while (i.hasNext()) {
////	             Observer o = (Observer) i.next();
////	             ((View)o).mutipleUpdate(data, id, result);
////	        }
//	}
//	
	@SuppressWarnings("unused")
	private void notifyObservers() {
	   Iterator<Observer> i = listeners.iterator();
       while (i.hasNext()) {
             Observer o = (Observer) i.next();
             o.update(null, o);
        }
	}	
	
}
